package io.mft.flow.core.executable.condition;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.mft.commons.function.ExecuteReturn;
import io.mft.commons.function.response.DsName;
import io.mft.commons.function.response.DsType;
import io.mft.commons.function.response.kv.PageObject;
import io.mft.flow.core.executable.ConditionExecutable;
import io.mft.flow.core.executable.ConditionType;
import io.mft.flow.core.executable.Executable;
import io.mft.flow.core.executable.ExecutableType;
import io.mft.flow.core.executable.drive.ConditionDriveSourceProvider;
import io.mft.flow.data.ChainContext;
import io.mft.flow.data.ExecutableResponse;
/**
 * 等待异步任务执行完成逻辑单元，用于多接口编排返回多结果集，一个接口请求等待多个逻辑单元执行完成，将多个逻辑单元的返回作为此编排接口的结果集返回
 * @说明：TODO
 * @类型名称：WaitWhenCondition
 * @创建者: 胡常建  
 * @创建时间: 2021年3月22日 下午4:04:50
 * @修改者: 胡常建  
 * @修改时间: 2021年3月22日 下午4:04:50
 */
public class SyncWaitAsyncCondition extends AsyncCondition implements ConditionDriveSourceProvider{

	public SyncWaitAsyncCondition(List<ConditionExecutable> nodeList) {
		super(nodeList);
	}

	@Override
	public ConditionType conditionType() {
		return ConditionType.syncWaitAsync;
	}

	private ExecuteReturn buildAsynResultToContextResponse(Map<ConditionExecutable, ExecutableResponse> responseMap,ChainContext context) {
		try {
			responseMap.entrySet().forEach(entry->{
				ExecutableResponse response=entry.getValue();
				response.getDsName().forEach(dsName->{
					String key=entry.getKey().getUniqueId()+"."+dsName.getName();
					String aliasName=entry.getKey().getExecutableId()+"."+dsName.getName();
					if (dsName.getType()==DsType.page) {
						PageObject<?> pageObject=response.pageTObject(dsName.getName());
						context.getResponse().resultObject(key, pageObject);
					}else {
						List<?> list=response.listObject(dsName.getName());
						context.getResponse().resultObject(key, dsName.getType(), list);
					}
					context.getResponse().getDsName(key).setAliasName(aliasName);
					context.getResponse().getDsName(key).setMainOutputDsKey(dsName.getMainOutputDsKey());
				});
			});
			return ExecuteReturn.builder().build();
		} catch (Exception e) {
			logger.error("",e);
			return ExecuteReturn.builder().code(-1).message(e.getMessage()).build();
		}
	}   
	@Override
	public ExecuteReturn execute(ChainContext context) throws Exception {
		List<ConditionExecutable> conditionExecutables=getNodeList();
		Map<ConditionExecutable, ExecutableResponse> responseMap=new HashMap<ConditionExecutable, ExecutableResponse>();
		List<ExecuteReturn> executeReturns=new ArrayList<>();
		for (ConditionExecutable conditionExecutable : conditionExecutables) {
			ExecutableResponse response=new ExecutableResponse();
			responseMap.put(conditionExecutable, response);
			String uniqueId = conditionExecutable.getUniqueId();
			ChainContext chainContext=new ChainContext(chainCondition.getChain().getChainId(),context.getRequest(),context.getRequest(), response,uniqueId);
			Executable executable=getFlowExecutor().getExecutable(ExecutableType.NODE,conditionExecutable.getExecutableId());
			ExecuteReturn executeReturn=executable.execute(chainContext);
			executeReturns.add(executeReturn);
		}
		executeReturns.forEach(executeReturn->{
			try {
				executeReturn.get(-1);//一直等待任务执行完成，返回结果
			} catch (Exception e) {
				logger.error("",e);
			}
		});
		ExecuteReturn executeReturn=buildAsynResultToContextResponse(responseMap, context);
		if (executeReturn.getCode()==0) {//当前逻辑单元正常返回则执行下一个逻辑单元节点
			if (chainCondition.getNextChainCondition() != null) {
				executeReturn = chainConditionDriver.drive(context,this);
			}
		}
		return executeReturn;
	}

	@Override
	public ProvideResult provide(ChainContext context) {
		ProvideResult provideResult=new ProvideResult();
		List<Object> list = new ArrayList<>();
		ConditionExecutable lastConditionExecutable = getLastConditionExecutable();
		List<DsName> dsNames = context.getResponse().getDsName();
		for (DsName dsName : dsNames) {
			if (dsName.getName().startsWith(lastConditionExecutable.getUniqueId())) {
				if (dsName.getName().endsWith(dsName.getMainOutputDsKey())) {
					List<Object> ts = context.getResponse().listObject(dsName.getName());
					list.addAll(ts);
					break;
				}
			}
		}
		provideResult.setList(list);
		return provideResult;
	}
}
